package com.landinfo.service.impl;

import com.landinfo.service.WordReportService;
import com.landinfo.web.rest.util.WordChartUtil;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.*;


@Service
@Transactional
public class WordReportServiceImpl implements WordReportService {

    @Autowired
    private HttpServletRequest request;

    @Override
    public String export() {
        try {
            File inFile = ResourceUtils.getFile("classpath:db/大熊猫固定样线监测工作模板.docx");
            // File outFile= new File(inFile.getParent()+File.pathSeparator+"一键生成报告"+UUID.randomUUID().toString()+".doc");
            File tempFile = new File(this.getApplicationPath());
            if (!tempFile.exists()) {
                tempFile.mkdirs();
            }
            String name=UUID.randomUUID().toString();
            String fileName="一键生成报告"+name+".doc";
            String fileNamePicture="一键生成报告"+name+".png";
            File outFile= new File(this.getApplicationPath()+File.separator+fileName);
            File outFilePicture= new File(this.getApplicationPath()+File.separator+fileNamePicture);
            String resultUrl="attached" + File.separator + "word_report" + File.separator+fileName;



            // 柱状图
            DefaultCategoryDataset chartDate = new DefaultCategoryDataset();
            chartDate.addValue(55, "访问量", "2010-01");
            chartDate.addValue(65, "访问量", "2010-02");
            chartDate.addValue(59, "访问量", "2010-03");
            chartDate.addValue(156, "访问量", "2010-04");
            chartDate.addValue(452, "访问量", "2010-05");
            chartDate.addValue(359, "访问量", "2010-06");
            String chartTitle="不同植被生境类型中野生大熊猫痕迹多度";
            String xFieldTitle="时间";
            String yFieldTitle="访问量";
            WordChartUtil.barChart3D(outFilePicture,chartDate,chartTitle,xFieldTitle,yFieldTitle);

            // 饼状图
            DefaultPieDataset dataType = new DefaultPieDataset();
            dataType.setValue("温性针阔滥交林", 156);
            dataType.setValue("落叶阔叶林", 230);
            dataType.setValue("常绿落叶阔叶滥交林", 45);
            dataType.setValue("温性针叶林", 640);
            WordChartUtil.pieChart(outFilePicture,dataType,chartTitle);

            // 曲线图
            // 时间序列对象集合
            TimeSeriesCollection chartTime = new TimeSeriesCollection();
            // 时间序列对象，第1个参数表示时间序列的名字，第2个参数是时间类型，这里为天
            // 该对象用于保存前count天每天的访问次数
            TimeSeries timeSeries = new TimeSeries("日访问");
            // 为了演示，直接拼装数据
            // Day的组装格式是day-month-year 访问次数
            timeSeries.add(new Day(1, 1, 2010), 50);
            timeSeries.add(new Day(2, 1, 2010), 47);
            timeSeries.add(new Day(3, 1, 2010), 82);
            timeSeries.add(new Day(4, 1, 2010), 95);
            timeSeries.add(new Day(5, 1, 2010), 104);
            timeSeries.add(new Day(6, 1, 2010), 425);
            chartTime.addSeries(timeSeries);
            WordChartUtil.SeriesChart(outFilePicture,chartTime,chartTitle,xFieldTitle,yFieldTitle);

            DefaultCategoryDataset dataTime = new DefaultCategoryDataset();
            // 这是一组数据
            dataTime.addValue(52, "0-6", "2010-1-1");
            dataTime.addValue(86, "6-12", "2010-1-1");
            dataTime.addValue(126, "12-18", "2010-1-1");
            dataTime.addValue(42, "18-24", "2010-1-1");
            // 这是一组数据
            dataTime.addValue(452, "0-6", "2010-1-2");
            dataTime.addValue(96, "6-12", "2010-1-2");
            dataTime.addValue(254, "12-18", "2010-1-2");
            dataTime.addValue(126, "18-24", "2010-1-2");
            // 这是一组数据
            dataTime.addValue(256, "0-6", "2010-1-3");
            dataTime.addValue(86, "6-12", "2010-1-3");
            dataTime.addValue(365, "12-18", "2010-1-3");
            dataTime.addValue(24, "18-24", "2010-1-3");
            WordChartUtil.SeriesMuliChart(outFilePicture,dataTime,chartTitle,xFieldTitle,yFieldTitle);







            Map<String, Object> data = new HashMap<String, Object>();
            data.put("标题年月.上下半年", "2018上");
            data.put("调查时间及工作量.调查时间", "10月-12月");
            data.put("调查时间及工作量.截至时间", "12月3日");
            data.put("调查时间及工作量.监测表格", "201");
            data.put("调查时间及工作量.大熊猫野外种群状况监测记录", "157");
            data.put("调查时间及工作量.主要野生动物种群状况监测表", "27");
            data.put("调查时间及工作量.大熊猫及其栖息地受干扰状况监测表", "17");
            data.put("大熊猫活动痕迹.大熊猫固定样线监测共记录", "大熊猫痕迹点51个，其中大熊猫粪便痕迹51处（新鲜10处，较新鲜13处，不新鲜28处），大熊猫食迹40处，大熊猫卧迹2处，发现大熊猫痕迹最多的区域为正河流域，其次为老鸦山、幸福沟、七层楼区域");
            data.put("大熊猫生境类型选择.大熊猫栖息地植被生境类型", "填写大熊猫野外种群状况监测记录表157份，共记录7种植被生境类型，分别为常绿落叶阔叶混交林、落叶阔叶林、温性针阔叶混交林、温性针叶林、灌草丛、山地人工林、农田，其中温性针阔混交林占比最大，达66.88%");
            data.put("大熊猫生境类型选择.同植被生境类型中野生大熊猫的痕迹多度", "三种植被类型中发现了野生大熊猫活动痕迹，分别为针阔混交林、常阔落阔混交林、落叶阔叶林，发现的51处野生大熊猫活动痕迹点，其中47处位于温性针阔混交林中，占比92.16%");
            data.put("大熊猫栖息地竹类.大熊猫取食竹种类", "本次调查，157份大熊猫野外种群状况监测记录表中有138份记录表记录到大熊猫取食竹，共记录到拐棍竹、冷箭竹、短锥玉山竹、华西箭竹四种竹类。其中拐棍竹占比最高，达52.17%，短锥玉山竹与冷箭竹占比相同，为23.19%");
            data.put("大熊猫栖息地竹类.不同大熊猫取食竹中野生大熊猫痕迹多度", "四种大熊猫取食竹林中，短锥玉山竹林中野生大熊猫的痕迹点数占总数的39.22%，冷箭竹林中野生大熊猫的痕迹点数占总数的35.29%，拐棍竹林中野生大熊猫的痕迹点数占总数的25.49%，华西箭竹竹林中未发现大熊猫活动痕迹");


            Map<String,Object> header = new HashMap<String, Object>();
            header.put("width",500);
            header.put("height",300);
            header.put("type","jpg");
            //header.put("content", inputStream2ByteArray(new FileInputStream("/Users/ziqilv/Pictures/大地吉信发票.jpeg"),true));
            header.put("file", "/Users/ziqilv/Pictures/大地吉信发票.jpeg");
            data.put("${img1}",header);



            List<String[]> testList = new ArrayList<String[]>();
            testList.add(new String[]{"1","1AA","1BB","1CC"});
            testList.add(new String[]{"2","2AA","2BB","2CC"});
            testList.add(new String[]{"3","3AA","3BB","3CC"});
            testList.add(new String[]{"4","4AA","4BB","4CC"});
            replaceWord(inFile.getAbsolutePath(), outFile.getAbsolutePath(), data, testList);
            return resultUrl;
//            this.readwriteWord(inFile,testMap);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据模板生成新word文档
     * 判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
     * @param inputUrl 模板存放地址
     * @param outPutUrl 新文档存放地址
     * @param data 需要替换的信息集合
     * @param tableList 需要插入的表格信息集合
     * @return 成功返回true,失败返回false
     */
    public boolean replaceWord(String inputUrl, String outPutUrl,Map<String, Object> data, List<String[]> tableList) {

        //模板转换默认成功
        boolean changeFlag = true;
        try {
//            方法1
            //获取docx解析对象
             XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//            CustomXWPFDocument document = new CustomXWPFDocument(POIXMLDocument.openPackage(inputUrl));
            //解析替换文本段落对象
            replaceText(document, data);
            //解析替换表格对象
            replaceTable(document, data, tableList);

//            方法二
//            XWPFDocument document = searchAndReplace(inputUrl,data);

            //生成新的word
            File file = new File(outPutUrl);
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();

        } catch (IOException e) {
            e.printStackTrace();
            changeFlag = false;
        }

        return changeFlag;

    }

    /**
     * 替换段落文本
     * @param document docx解析对象
     * @param textMap 需要替换的信息集合
     */
    public void replaceText(XWPFDocument document, Map<String, Object> textMap){
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();

        for (XWPFParagraph paragraph : paragraphs) {
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if(checkText(text)){
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    // run.setText(changeValue(run.toString(), textMap),0);

                    Object resultValue=changeValue(run.toString(), textMap);
                    if (resultValue instanceof String){
                        run.setText(resultValue.toString(),0);
                    }else if (resultValue instanceof Map) {
                        Map pic = (Map) resultValue;
                        int width = Integer.parseInt(pic.get("width").toString());
                        int height = Integer.parseInt(pic.get("height").toString());
                        int picType = getPictureType(pic.get("type").toString());
                        String pictureFile = pic.get("file").toString();
                        FileInputStream is = null;
                        try {
                            is = new FileInputStream(pictureFile);
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                        // run.addBreak();
                        run.setText("",0);
                        try {
                            // run.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
                            run.addPicture(is, picType, pictureFile, Units.toEMU(width), Units.toEMU(height)); // 200x200 pixels
                        } catch (InvalidFormatException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
//                        try {
//                            is.close();
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//
//                        FileOutputStream fos = null;
//                        try {
//                            fos = new FileOutputStream(output);
//                        } catch (FileNotFoundException e) {
//                            e.printStackTrace();
//                        }
//                        try {
//                            doc.write(fos);
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//                        try {
//                            fos.close();
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }

                    }
                }
            }
        }

    }



    /**
     * 替换表格对象方法
     * @param document docx解析对象
     * @param textMap 需要替换的信息集合
     * @param tableList 需要插入的表格信息集合
     */
    public static void replaceTable(XWPFDocument document, Map<String, Object> textMap,List<String[]> tableList){
        //获取表格对象集合
        List<XWPFTable> tables = document.getTables();
        for (int i = 0; i < tables.size(); i++) {
            //只处理行数大于等于2的表格，且不循环表头
            XWPFTable table = tables.get(i);
            if(table.getRows().size()>1){
                //判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
                if(checkText(table.getText())){
                    List<XWPFTableRow> rows = table.getRows();
                    //遍历表格,并替换模板
                    eachTable(rows, textMap);
                }else{
//                  System.out.println("插入"+table.getText());
                    insertTable(table, tableList);
                }
            }
        }
    }





    /**
     * 遍历表格
     * @param rows 表格行对象
     * @param textMap 需要替换的信息集合
     */
    public static void eachTable(List<XWPFTableRow> rows ,Map<String, Object> textMap){
        for (XWPFTableRow row : rows) {
            List<XWPFTableCell> cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                //判断单元格是否需要替换
                if(checkText(cell.getText())){
                    List<XWPFParagraph> paragraphs = cell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs) {
                        List<XWPFRun> runs = paragraph.getRuns();
                        for (XWPFRun run : runs) {
                            Object object=changeValue(run.toString(), textMap);

                            run.setText(object.toString(),0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 为表格插入数据，行数不够添加新行
     * @param table 需要插入数据的表格
     * @param tableList 插入数据集合
     */
    public static void insertTable(XWPFTable table, List<String[]> tableList){
        //创建行,根据需要插入的数据添加新行，不处理表头
        for(int i = 1; i < tableList.size(); i++){
            XWPFTableRow row =table.createRow();
        }
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        for(int i = 1; i < rows.size(); i++){
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for(int j = 0; j < cells.size(); j++){
                XWPFTableCell cell = cells.get(j);
                try {
                    cell.setText(tableList.get(i - 1)[j]);
                }catch (Exception ex){

                }
            }
        }

    }



    /**
     * 判断文本中时候包含$
     * @param text 文本
     * @return 包含返回true,不包含返回false
     */
    public static boolean checkText(String text){
        boolean check  =  false;
        if(text.indexOf("$")!= -1){
            check = true;
        }
        return check;

    }

    /**
     * 匹配传入信息集合与模板
     * @param value 模板需要替换的区域
     * @param textMap 传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    public static Object changeValue(String value, Map<String, Object> textMap){
        Object resultValue=value;
        Set<Map.Entry<String, Object>> textSets = textMap.entrySet();
        for (Map.Entry<String, Object> textSet : textSets) {
            //匹配模板与替换值 格式${key}
            String key = "${"+textSet.getKey()+"}";
            if(value.indexOf(key)!= -1 || key.indexOf(value) !=-1){
                value = textSet.getValue().toString();
                resultValue=textSet.getValue();
            }
        }
        //模板未匹配到区域替换为空
        if(checkText(value)){
            value = "";
            resultValue="";
        }
        // return value;
        return resultValue;
    }


    private int getPictureType(String picType) {
        int res = XWPFDocument.PICTURE_TYPE_PICT;
        if (picType != null) {
            if (picType.equalsIgnoreCase("png")) {
                res = XWPFDocument.PICTURE_TYPE_PNG;
            } else if (picType.equalsIgnoreCase("dib")) {
                res = XWPFDocument.PICTURE_TYPE_DIB;
            } else if (picType.equalsIgnoreCase("emf")) {
                res = XWPFDocument.PICTURE_TYPE_EMF;
            } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
                res = XWPFDocument.PICTURE_TYPE_JPEG;
            } else if (picType.equalsIgnoreCase("wmf")) {
                res = XWPFDocument.PICTURE_TYPE_WMF;
            }
        }
        return res;
    }



    /**
     * 获取应用程序路径
     *
     * @return
     */
    private String getApplicationPath() {
        String rootPath = request.getSession().getServletContext().getRealPath("/") + File.separator + "attached" + File.separator + "word_report" + File.separator;
        return rootPath;
    }
}
